﻿using System.IO;
using System.Security.Cryptography;
using System.Text;
using System;
using System.Collections.Generic;

namespace Framework
{
    public static class MD5Util
    {
        /// <summary>
        /// 计算文件的md5值
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>十六进制字符串</returns>
        public static string ComputeFileMd5(string filePath)
        {
            if (!File.Exists(filePath))
            {
                Logger.LogError($"MD5Util.ComputeFileMd5, filepath = {filePath} not exists!");
                return null;
            }
            string ret = null;
#if UNITY_IOS && !UNITY_EDITOR
            var jsonArgs = JsonHelper.Serialize(new Dictionary<string, string>()
            {
                {"path", filePath},
            });
            ret = NativeUtil.StringCallNative("GameNative", "calculateFileMd5", jsonArgs);
            if(!string.IsNullOrEmpty(ret))
            {
                ret = ret.ToUpper();
            }
#else 
            using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read))
            {
                byte[] hash = MD5.Create().ComputeHash(fs); ;
                fs.Close();
                var strBuilder = new StringBuilder();
                foreach (var item in hash)
                {
                    strBuilder.Append(item.ToString("x2"));
                }
                ret = strBuilder.ToString();
            }
#endif
            return ret;
        }
        /// <summary>
        /// 计算文件的md5值 十六进制字符串 小写
        /// </summary>
        /// <param name="filePath">文件路径</param>
        /// <returns>十六进制字符串 小写</returns>
        public static string ComputeFileMd5Lower(string filePath)
        {
            string ret = ComputeFileMd5(filePath);
            if (string.IsNullOrEmpty(ret))
            {
                return null;
            }
            return ret.ToLower();
        }

        /// <summary>
        /// 计算字符串的md5值 
        /// </summary>
        /// <param name="str">输入字符串</param>
        /// <returns>十六进制字符串</returns>
        public static string ComputeMd5(string str)
        {
            return ComputeMd5Str(Encoding.UTF8.GetBytes(str));
        }

        /// <summary>
        /// 计算md5值
        /// </summary>
        /// <param name="bytes">数据</param>
        /// <returns>md5数据</returns>
        public static byte[] ComputeMd5(byte[] bytes)
        {
            return ComputeMd5(bytes, 0, bytes.Length);
        }

        public static byte[] ComputeMd5(byte[] buffer, int offset, int count)
        {
            return MD5.Create().ComputeHash(buffer, offset, count);
        }

        /// <summary>
        /// 计算md5
        /// </summary>
        /// <param name="data">数据</param>
        /// <returns>md5的十六进制字符串</returns>
        public static string ComputeMd5Str(byte[] data)
        {
            var strBuilder = new StringBuilder();
            byte[] md5Data = ComputeMd5(data);
            foreach (var item in md5Data)
            {
                strBuilder.Append(item.ToString("x2"));
            }
            return strBuilder.ToString();
        }

        /// <summary>
        /// 计算md5签名
        /// </summary>
        /// <param name="data">数据</param>
        /// <returns>md5数据的base64字符串</returns>
        public static string ComputeMd5Sign(byte[] data)
        {
            byte[] md5Data = ComputeMd5(data);
            return System.Convert.ToBase64String(md5Data);
        }

        public static string ComputeMd5Sign(byte[] buffer, int offset, int count)
        {
            byte[] md5Data = ComputeMd5(buffer, offset, count);
            return System.Convert.ToBase64String(md5Data);
        }

        /// <summary>
        /// 对称AES加密算法
        /// </summary>
        /// <param name="srcStr">需要加密的字符串</param>
        /// <param name="password">密码</param>
        /// <param name="keyVector">加密向量</param>
        /// <returns></returns>
        public static byte[] AESEncrypt(string srcStr, byte[] password, byte[] keyVector)
        {
            if (srcStr == null || srcStr.Length <= 0)
                throw new ArgumentNullException("MD5Util.AESEncrypt, srcStr");
            if (password == null || password.Length <= 0)
                throw new ArgumentNullException("MD5Util.AESEncrypt, password");
            if (keyVector == null || keyVector.Length <= 0)
                throw new ArgumentNullException("MD5Util.AESEncrypt, keyVector");
            byte[] encrypted;
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = password;
                aesAlg.IV = keyVector;
                ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msEncrypt = new MemoryStream())
                {
                    using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
                    {
                        using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                        {
                            swEncrypt.Write(srcStr);
                        }
                        encrypted = msEncrypt.ToArray();
                    }
                }
            }
            return encrypted;
        }

        /// <summary>
        /// 对称AES解密算法
        /// </summary>
        /// <param name="encryptedData">已经加密的数据</param>
        /// <param name="password">密码</param>
        /// <param name="keyVector">加密向量</param>
        /// <returns></returns>
        public static string AESDecrypt(byte[] encryptedData, byte[] password, byte[] keyVector)
        {
            return AESDecrypt(encryptedData, 0, encryptedData.Length, password, keyVector);
        }

        public static string AESDecrypt(byte[] encryptedData, int offset, int count, byte[] password, byte[] keyVector)
        {
            if (encryptedData == null || encryptedData.Length <= 0)
                throw new ArgumentNullException("MD5Util.AESDecrypt, buffer");
            if (password == null || password.Length <= 0)
                throw new ArgumentNullException("MD5Util.AESDecrypt, password");
            if (keyVector == null || keyVector.Length <= 0)
                throw new ArgumentNullException("MD5Util.AESDecrypt, keyVector");

            string plaintext = null;
            using (Aes aesAlg = Aes.Create())
            {
                aesAlg.Key = password;
                aesAlg.IV = keyVector;
                ICryptoTransform decryptor = aesAlg.CreateDecryptor(aesAlg.Key, aesAlg.IV);
                using (MemoryStream msDecrypt = new MemoryStream(encryptedData, offset, count))
                {
                    using (CryptoStream csDecrypt = new CryptoStream(msDecrypt, decryptor, CryptoStreamMode.Read))
                    {
                        using (StreamReader srDecrypt = new StreamReader(csDecrypt))
                        {
                            plaintext = srDecrypt.ReadToEnd();
                        }
                    }
                }
            }
            return plaintext;
        }
    }
}
